package com.gxs.waqas.localfolders.utils;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.CopyOption;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Scanner;

import com.gxs.waqas.localfolders.pojo.ChecksumEntry;

public class ChecksumComparator implements Comparator<String>
{
	private static int duplicate = 0;
	private static int non_duplicate = 0;
	private static Map<String, Integer> folders = new HashMap<String, Integer>();
	private static Properties mapOfPreferredFolders;
	private static Map<String, String> initialMapOfPreferredFolders = new HashMap<String, String>();
	/**
	 * 
	 * @param args
	 */
	public static void main(String [] args)
	{
		try
		{
			String checksumFile = "S:\\checksums.csv";
			ChecksumLoader loader = new ChecksumLoader();
			loader.loadChecksumsIntoMaps(checksumFile);
			doChecksumComparisonWithinTheMasterFolderAndReportDuplicates(loader, new File("S:\\Pictures and Videos\\ORGANIZED_CAMERA_PICTURES"));;
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}
	
	private static void findAndCleanDuplicatesWithinEachFolder(ChecksumLoader loader) throws Exception
	{
		int fileRemovalCount = 0;
		
		for (String folder : loader.mapOfAllEntriesByFolder.keySet())
		{
			
			List<ChecksumEntry> listOfAllEntriesForGivenFolder = loader.mapOfAllEntriesByFolder.get(folder);
			//System.out.println("Analyzing Folder: " + folder + ", number of files: " + list.size());
			
			HashMap<String, List<ChecksumEntry>> uniqueFilesWithinFolder = new HashMap<String, List<ChecksumEntry>>();
			int duplicates = 0;
			String duplicateExample = "";
			
			// iterate over all files in this folder
			for(ChecksumEntry entry : listOfAllEntriesForGivenFolder)
			{
				String checkSum = entry.getChecksum();
				
				List<ChecksumEntry> filesForCurrentChecksum = uniqueFilesWithinFolder.get(checkSum);
				
				if(filesForCurrentChecksum == null)
				{
					filesForCurrentChecksum = new ArrayList<ChecksumEntry>();
					uniqueFilesWithinFolder.put(checkSum, filesForCurrentChecksum);
					filesForCurrentChecksum.add(entry);
				}
				else
				{
					duplicateExample = "Dup Example: " + entry.getAbsolutePath() + " :: " + filesForCurrentChecksum.get(0).getAbsolutePath() ;
					filesForCurrentChecksum.add(entry);
					duplicates++;
				}
			}
			
			if(duplicates > 0)
			{
				System.out.print("Folder :: " + folder + " :: has " + duplicates + " duplicate entry groupings :: ");
				System.out.println(duplicateExample);
			}
			
			for(String checksum : uniqueFilesWithinFolder.keySet() )
			{
				List<ChecksumEntry> listOfEntriesForCurrentChecksum = uniqueFilesWithinFolder.get(checksum);
				List<String> filesToBeRemoved = new ArrayList<String>();

				if(listOfEntriesForCurrentChecksum.size() > 1)
				{
					fileRemovalCount++;

					for(ChecksumEntry tempEntry : listOfEntriesForCurrentChecksum)
					{
						filesToBeRemoved.add(tempEntry.getAbsolutePath());
					}
					
					Collections.sort(filesToBeRemoved, new ChecksumComparator());
					
					System.out.println("\t\t" + fileRemovalCount + " :: File removal order: " + filesToBeRemoved);
				
					//
					// Remove files, starting from index 1
					
					for(int i=1; i<filesToBeRemoved.size(); i++)
					{
						removeDuplicateFile(filesToBeRemoved.get(i));
					}
				}
				
				
			}
			
		}
		
	}


	private static void removeDuplicateFile(String sourcePath) throws IOException 
	{
		String destinationPath = sourcePath.replace("ORGANIZED_CAMERA_PICTURES", "_duplicates");
		File destinationDirectory = new File(destinationPath).getParentFile();
		if(! destinationDirectory.exists() )
		{
			destinationDirectory.mkdirs();
		}
		
		Files.move(FileSystems.getDefault().getPath(sourcePath), FileSystems.getDefault().getPath(destinationPath), StandardCopyOption.REPLACE_EXISTING);
	}


	private static void doChecksumComparisonWithinTheMasterFolderAndReportDuplicates(	ChecksumLoader loader, File file) throws Exception 
	{
		Map<String, List<ChecksumEntry>> mapOfEntries = loader.mapOfAllEntriesByChecksum;
		Map<String, Integer> mapOfDuplicateFolders = new HashMap<String, Integer>();
		
		System.out.println("Total Files in checksum list: " + loader.mapOfFilesByAbsoluatePath.size() + ", and Unique Files: " + loader.mapOfAllEntriesByChecksum.size() );
		int dupCount = 0;
		for(String checksum : mapOfEntries.keySet() )
		{
			List<ChecksumEntry> list = mapOfEntries.get(checksum);
			
			if(list.size() < 2)
				continue;
			
			dupCount++;
			System.out.print("Duplicate " + dupCount + " :: "  + list.size() + " files :: ");
			
			for(ChecksumEntry entry : list)
			{
				System.out.print(entry.getAbsolutePath() + " :: ");
			}
			
			System.out.println();
			
			String key = getAlphabetizedListOfFolderNames(list, true);
			 
			String preferredFolder = initialMapOfPreferredFolders.get(key);
			File preferredFolderFile = new File(preferredFolder);
			
			if(preferredFolder == null || ! preferredFolderFile.exists())
			{
				System.out.println("Preferred folder does not exist");
			}
			
			if(mapOfDuplicateFolders.get(key) == null)
			{
				mapOfDuplicateFolders.put(key, new Integer(1));
			}
			else
			{
				Integer value = mapOfDuplicateFolders.get(key);
				mapOfDuplicateFolders.put(key, new Integer(value+1));
			}
			
			deleteDuplicateFileFromMasterFolder(list, preferredFolder);
		}
		
		int count = 0;
		for(String f : mapOfDuplicateFolders.keySet())
		{
			count++;
			Integer value = mapOfDuplicateFolders.get(f);
			//System.out.println(count + "~DUPLICATE FOLDRES~" + value + "~onflicts, ~folders~" + f);
			System.out.println(f);
		}
		
		for(String key : initialMapOfPreferredFolders.keySet() )
		{
			System.out.println(key + "=" + initialMapOfPreferredFolders.get(key));
		}
	}

	private static void deleteDuplicateFileFromMasterFolder(
			List<ChecksumEntry> list, String preferredFolder) throws IOException
	{
		File preferredFolderFile = new File("S:\\Pictures and Videos\\ORGANIZED_CAMERA_PICTURES", preferredFolder);
		ChecksumEntry entryToKeep = null;
		for(ChecksumEntry entry : list)
		{
			File currentFile = new File(entry.getAbsolutePath());
			String currentAbsoluteFolderPath = currentFile.getParent();
			if(currentAbsoluteFolderPath.equals(preferredFolderFile.getAbsolutePath() ) )
			{
				entryToKeep = entry;
			}
		}
		
		list.remove(entryToKeep);
		list.add(0, entryToKeep);
		
		for(int i=1; i<list.size(); i++)
		{
			String duplicateFile = list.get(i).getAbsolutePath();
			System.out.println("Removing duplicate file: " + duplicateFile);
			removeDuplicateFile(duplicateFile);
		}
		
	}

	private static File getPreferredFolder(String key) throws FileNotFoundException, IOException 
	{
		if(mapOfPreferredFolders == null)
		{
			mapOfPreferredFolders = new Properties();
			mapOfPreferredFolders.load(new FileInputStream("S:\\preferredFolders.properties"));
			mapOfPreferredFolders.put("013-Duplicate-BabySelections*Salma-s iPhone*", "Salma-s iPhone");
		}
		
		key = key.trim();
		
		String preferredFolder = (String) mapOfPreferredFolders.get(key);
		if(preferredFolder == null)
		{
			System.out.println("\t\tPreferred folder entry not found for key: ->"  + key + "<-");
			System.in.read();
		}
		File preferredFolderFile = new File("S:\\Pictures and Videos\\ORGANIZED_CAMERA_PICTURES", preferredFolder);
		
		if(! preferredFolderFile.exists() )
		{
			System.out.println("\t\tPreferred folder does not exist: " + preferredFolder);
			System.in.read();
		}
		
		System.out.println("\t\t" + preferredFolder + " \t\t\tis the preferred folder for : " + key);
		return preferredFolderFile;
	}

	public static String getAlphabetizedListOfFolderNames(List<ChecksumEntry> list, boolean askForPreferredFolder)
	{
		List<String> listOfFoldernames = new ArrayList<String>();
		
		for(ChecksumEntry entry: list)
		{
			File folder = new File(entry.getAbsolutePath());
			listOfFoldernames.add(folder.getParentFile().getName());
		}
		
		Collections.sort(listOfFoldernames);

		String returnString = "";
		
		for(String key: listOfFoldernames)
		{
			returnString = returnString + key + "*";
		}
		

		if(askForPreferredFolder)
		{
		/*
		 * Save replacemnet
		 */
		if(initialMapOfPreferredFolders.get(returnString) == null)
		{

			System.out.println("\nChoose Preferred Folder >>: ");
			for(int index = 0; index < listOfFoldernames.size(); index++)
			{
				System.out.println("\t\t[" + index + "] : " + listOfFoldernames.get(index));
			}

			System.out.print("Folder Index: >>");
			Scanner scanner = new Scanner(System.in);
			String input = scanner.next();
			int pref = Integer.parseInt(input);
			
			initialMapOfPreferredFolders.put(returnString, listOfFoldernames.get(pref) );
		}
		}

		
		return returnString;
		
	}
	private static void doCheckSumComparisonForDeletesBetweenTwoDrives() throws Exception
	{
		String checksumFile = "S\\checksums.csv";
		String location = "S:\\Pictures and Videos\\flickr";
		String deletedLocation = "S:\\Pictures and Videos\\_deleted";
		//String location = "S:\\Pictures and Videos\\ORGANIZED_CAMERA_PICTURES";
		ChecksumLoader loader = new ChecksumLoader();
		loader.loadChecksumsIntoMaps(checksumFile);
		doChecksumComparisons(new File(location), new File(deletedLocation), loader);
		System.out.println("------------");
		for(String f : folders.keySet() )
		{
			System.out.println(f);
		}

	}
	/**
	 * 
	 * @param checksumFile
	 * @param location
	 * @param loader 
	 * @throws Exception
	 */
	private static void doChecksumComparisons(File location, File deleteLocationx, ChecksumLoader loader) throws Exception 
	{
		File [] listOfPotentialFolders = location.listFiles();
		
		for(int i=0; i<listOfPotentialFolders.length; i++)
		{
			File currentFile = listOfPotentialFolders[i];
			
			if(currentFile.isDirectory())
			{
				doChecksumComparisons(currentFile, deleteLocationx, loader);
			}
			else
			{
				
				String checkSum = ChecksumCalculator.getCheckSumOfFile(currentFile.getAbsolutePath());
				
				ChecksumEntry entry = loader.mapOfFilesByChecksum.get(checkSum);
				
				if(entry != null)
				{
					duplicate++;
					System.out.println("Duplicate: " + duplicate + ", non-duplicate: " +  non_duplicate + " :: Duplicate found at : " + currentFile.getAbsolutePath() + " :: Duplicate with :: " + entry.getFolderAndFileName());
//					String currentLocation = currentFile.getParentFile().getAbsolutePath();
//					File newLocation = new File(currentLocation.replace("_allOtherFolders", "_deleted"));
//					if(! newLocation.exists())
//					{
//						newLocation.mkdirs();
//					}
//					
//					System.out.println("\t\tMoving file to directory: " + newLocation + ", with name: " + currentFile.getName());
//					
//				
//					File destinationFile = new File(newLocation, currentFile.getName());
//					Files.move(FileSystems.getDefault().getPath(currentFile.getAbsolutePath()), FileSystems.getDefault().getPath(destinationFile.getAbsolutePath()), StandardCopyOption.REPLACE_EXISTING);
//					
				}
				else
				{
					non_duplicate ++;
					if(folders.get(currentFile.getParent()) == null )
					{
						folders.put(currentFile.getParent(), 1);
					}
					System.out.println("Duplicate: " + duplicate + ", non-duplicate: " +  non_duplicate + " :: NON Duplicate found at : " + currentFile.getAbsolutePath() );
				}
			}
				
		}
		
		
	}

	public int compare(String fileName, String fileName2) 
	{
		if(fileName.length() < fileName2.length() )
		{
			return -1;
		}
		else if(fileName.length() > fileName2.length())
		{
			return 1;
		}
		else
		{
			return 0;
		}
	}

}
